﻿using System;
using System.Linq;
using System.Reflection;
using System.Data;
using System.Collections.Generic;
using System.Windows.Forms;
using UtfprLibrary.Windows.Forms.Exceptions;
using UtfprLibrary.Windows.Forms.Extensions;
using UtfprLibrary.Windows.Forms.ComponentModel;


namespace UtfprLibrary.Windows.Forms.Helpers {
    public static class UtfprBindingNavigatorBaseHelper2 {
        public static List<Control> GetAllBindableControls(UtfprBindingNavigatorBase navigator) {
            try {
                return UtfprControlHelper.FindControls(UtfprControlHelper.FindForm(navigator).Controls)
                    .Where(c => c.IsBindible())
                    .ToList();
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        public static List<Control> GetJustBindableControlsFrom(UtfprBindingNavigatorBase navigator) {
            try {
                return UtfprControlHelper.FindControls(UtfprControlHelper.FindForm(navigator).Controls)
                    .Where(c => c.IsBindibleFrom(navigator))
                    .ToList();
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        public static BindingSource GetMasterBindingSource(UtfprBindingNavigatorBase navigator) {
            try {
                var rootSource = navigator;
                while (rootSource != null && rootSource.CurrentMode != UBNModeEnum.Master) {
                    rootSource = rootSource.NavigatorSource;
                }

                if (rootSource == null) {
                    rootSource = UtfprControlHelper.FindControls(UtfprControlHelper.FindForm(navigator).Controls)
                        .OfType<UtfprBindingNavigatorBase>()
                        .Where(c => c.CurrentMode == UBNModeEnum.Master)
                        .FirstOrDefault();
                }

                if (!(rootSource.DataSource is BindingSource)) {
                    throw new ArgumentException("DataSource is not typeof(BindingSource)");
                }

                return rootSource.DataSource as BindingSource;
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }
    }

    /// <summary>
    /// A static class used to help with UtfprBindingNavigatorBase logic
    /// </summary>
    public static class UtfprBindingNavigatorBaseHelper {
        #region find/get

        /// <summary>
        /// Find the root UtfprBindingNavigatorBase
        /// </summary>
        /// <param name="navigator">a UtfprBindingNavigatorBase used to start searching (with NavigatorSource property)</param>
        /// <returns>the root UtfprBindingNavigatorBase</returns>
        public static UtfprBindingNavigatorBase findRootSourceNavigator(UtfprBindingNavigatorBase navigator) {
            try {
                var rootSource = navigator;
                while (rootSource != null && rootSource.CurrentMode != UBNModeEnum.Master) {
                    rootSource = rootSource.NavigatorSource;
                }

                if (rootSource == null) {
                    rootSource = getRootFormControls(navigator).OfType<UtfprBindingNavigatorBase>()
                        .Where(c => c.CurrentMode == UBNModeEnum.Master).FirstOrDefault();
                }

                return rootSource;
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// Find the root UtfprBindingNavigatorBase
        /// </summary>
        /// <param name="form">a Form which contains the root UtfprBindingNavigatorBase used to start searching (with NavigatorSource property)</param>
        /// <returns>the root UtfprBindingNavigatorBase</returns>
        public static UtfprBindingNavigatorBase findRootSourceNavigator(Form form) {
            try {
                var flags = BindingFlags.NonPublic | BindingFlags.Instance;
                var allFields = new List<FieldInfo>();
                allFields.AddRange(form.GetType().GetFields(flags)); //inheritance
                allFields.AddRange(form.GetType().BaseType.GetFields(flags));//composition
                
                return (from info in allFields
                        where info.FieldType == typeof(UtfprBindingNavigatorBase)
                        select info.GetValue(form) as UtfprBindingNavigatorBase)
                        .Where(navigator => navigator.CurrentMode == UBNModeEnum.Master)
                        .SingleOrDefault();
                
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// Get all Controls in the root form of a UtfprBindingNavigatorBase
        /// </summary>
        /// <param name="navigator">the UtfprBindingNavigatorBase used in the search</param>
        /// <returns>the list of Controls</returns>
        internal static List<Control> getRootFormControls(UtfprBindingNavigatorBase navigator) {
            try {
                return UtfprControlHelper.FindControls(UtfprControlHelper.FindForm(navigator).Controls);
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// Get all DataGridViews in the root form of a UtfprBindingNavigatorBase
        /// </summary>
        /// <param name="navigator">the UtfprBindingNavigatorBase used in the search</param>
        /// <returns>the list of DataGridViews</returns>
        internal static List<DataGridView> getRootFormDataGrids(UtfprBindingNavigatorBase navigator) {
            try {
                return UtfprControlHelper.findDataGridViews(UtfprControlHelper.FindForm(navigator).Controls);
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// Get all UtfprLookupFields in the root form of a UtfprBindingNavigatorBase
        /// </summary>
        /// <param name="navigator">the UtfprBindingNavigatorBase used in the search</param>
        /// <returns>the list of UtfprLookupFields</returns>
        internal static List<UtfprLookupFieldBase> getRootFormLookups(UtfprBindingNavigatorBase navigator) {
            try {
                var rootForm = UtfprControlHelper.FindForm(navigator);
                var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;

                //var fields = rootForm.GetType().GetFields(flags).Where(f => f.FieldType == typeof(UtfprLookupFieldBase));

                var fields = rootForm.GetType().GetFields(flags).Where(f => typeof(UtfprLookupFieldBase).IsAssignableFrom(f.FieldType));

                var lookupFieldsValidators = new List<UtfprLookupFieldBase>();
                foreach (var field in fields) {
                    lookupFieldsValidators.Add(field.GetValue(rootForm) as UtfprLookupFieldBase);
                }
                return lookupFieldsValidators;
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// Try to find an EntityKey and it's value
        /// </summary>
        /// <param name="entity">an entity object</param>
        /// <returns>a value if the entity contains an EntityKey, otherwise null</returns>
        public static object getEntityKeyValue(object entity) {
            try {
                var key = entity.GetType().GetProperties()
                    .Where(p => p.PropertyType == typeof(EntityKey))
                    .FirstOrDefault().GetValue(entity, null) as EntityKey;

                if (key != null) {
                    return key.EntityKeyValues.FirstOrDefault().Value;
                }

                return null;
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        public static object getCurrentEntity(UtfprFormQueryBase formQuery) {
            try {
                if (formQuery.ShowDialog() == DialogResult.OK) {
                    return formQuery.GetCurrentEntity();
                }
                return null;
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        internal static UtfprFormCrudBase getUtfprCrud(UtfprBindingNavigatorBase navigator) {
            try {
                if (!navigator.UtfprControlBase.IsInDesignMode) {
                    var form = UtfprControlHelper.FindForm(navigator);
                    var formFullName = form.GetType().FullName;

                    if (formFullName == UtfprWindowsFormsConsts.UtfprFormCrud_FullName || formFullName == UtfprWindowsFormsConsts.UtfprFormCrudBase_FullName) {
                        return form as UtfprFormCrudBase;
                    }

                    formFullName = form.GetType().BaseType.FullName;

                    if (formFullName == UtfprWindowsFormsConsts.UtfprFormCrud_FullName || formFullName == UtfprWindowsFormsConsts.UtfprFormCrudBase_FullName) {
                        return form as UtfprFormCrudBase;
                    }
                }
                return null;
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        internal static UtfprFormQueryBase getUtfprQuery(UtfprFormCrudBase formCrud) {
            try {
                if (formCrud != null) {
                    return formCrud.GetUtfprQuery();
                }
                return null;
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        private static List<UtfprBindingNavigatorBase> getRootFormNavigators(UtfprBindingNavigatorBase navigator) {
            try {
                return getNavigators(UtfprControlHelper.FindForm(navigator).Controls);
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        private static List<UtfprBindingNavigatorBase> getNavigators(Control.ControlCollection controls) {
            try {
                var navigators = new List<UtfprBindingNavigatorBase>();

                foreach (Control control in controls) {
                    if (control.GetType() == typeof(UtfprBindingNavigatorBase)) {
                        navigators.Add(control as UtfprBindingNavigatorBase);
                    } else {
                        var innerNavigators = getNavigators(control.Controls);

                        for (int i = 0; i < innerNavigators.Count; i++) {
                            navigators.Add(innerNavigators[i]);
                        }
                    }
                }

                return navigators;
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        internal static List<UtfprLookupFieldBase> getInnerLookups(UtfprBindingNavigatorBase navigator) {
            try {
                var innerLookupFields = new List<UtfprLookupFieldBase>();
                //listo todos os lookups
                foreach (var lookup in UtfprBindingNavigatorBaseHelper.getRootFormLookups(navigator)) {
                    if (lookup.LookupSource != null) {

                        //var isInnerLookup = getRootSources(navigator).Where(s => s.BindingSource == lookup.LookupSource).Count() == 0;
                        var isInnerLookup = getRootSources(navigator).Where(s => s.DataSource == lookup.LookupSource).Count() == 0;
                        if (isInnerLookup) {
                            innerLookupFields.Add(lookup);
                        }

                        //foreach (Binding binding in lookup.DataBindings) {
                        //    if (binding.PropertyName == "LookupMember") {
                        //        //verifico se é um lookup de nível abaixo
                        //        var isInnerLookup = getRootSources(navigator).Where(s => s.BindingSource == binding.DataSource).Count() == 0;
                        //        if (isInnerLookup) {
                        //            innerLookupFields.Add(lookup);
                        //        }
                        //    }
                        //}
                    }
                }

                return innerLookupFields;
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        public static List<UtfprBindingNavigatorBase> getInnerSources(UtfprBindingNavigatorBase navigator) {
            try {
                var rootSources = getRootSources(navigator);
                rootSources.Add(navigator);
                return findRootSourceNavigator(navigator).UBNDetails.Except(rootSources).ToList();
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        internal static List<UtfprBindingNavigatorBase> getRootSources(UtfprBindingNavigatorBase navigator) {
            try {
                var rootSources = new List<UtfprBindingNavigatorBase>();
                while (navigator.CurrentMode != UBNModeEnum.Master) {
                    navigator = navigator.NavigatorSource;
                    rootSources.Add(navigator);

                    if (navigator == null) {
                        throw new Exception("navigator cannot be null.");
                    }
                }
                return rootSources;
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        #endregion

        #region enable/disable

        /// <summary>
        /// TODO
        /// </summary>
        public static void bindingsEnabled(UtfprBindingNavigatorBase navigator, bool enabled) {
            try {
                if (navigator == null) {
                    throw new ArgumentNullException("navigator cannot be null.");
                }

                if (navigator.DataSource == null) {
                    throw new ArgumentNullException("DataSource cannot be null.");
                }

                var rootFormControls = getRootFormControls(navigator)
                    .Where(c => c.DataBindings.Count > 0);


                foreach (Control c in rootFormControls) {
                    //if (navigator.BindingSource.DataMember == ((BindingSource)c.DataBindings[0].DataSource).DataMember) {
                    //talves aqui tenha problemas
                    if (navigator.DataSource is BindingSource) {
                        if (((BindingSource)navigator.DataSource).DataMember == ((BindingSource)c.DataBindings[0].DataSource).DataMember) {
                            c.DataBindings[0].BindableComponent.DataBindings.Control.Enabled = enabled;
                        }
                    }
                }

                var lookups = getRootFormControls(navigator)
                    .Where(c => c.GetType() == typeof(UtfprLookupFieldBase));

                foreach (Control c in lookups) {
                    if (navigator.DataSource == ((UtfprLookupFieldBase)c).LookupSource) {
                        //if (navigator.BindingSource == ((UtfprLookupField)c).LookupSource) {
                        c.Enabled = enabled;
                    }
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        public static void innerDetailsEnabled(UtfprBindingNavigatorBase navigator, bool enabled) {
            try {
                foreach (var innerSource in getInnerSources(navigator).ToList()) {
                    //if (innerSource.List.Count > 0) {
                    //if (innerSource.BindingSource.List.Count > 0) {
                    if (navigator.NavigatorSource != innerSource.NavigatorSource) {
                        if (navigator.DataSource is BindingSource) {
                            if (((BindingSource)innerSource.DataSource).List.Count > 0) {
                                innerSource.DeleteItem.UtfprControlEnabled = true;
                                innerSource.EditItem.UtfprControlEnabled = true;
                            } else {
                                innerSource.DeleteItem.UtfprControlEnabled = false;
                                innerSource.EditItem.UtfprControlEnabled = false;
                            }
                        }
                        if (!enabled) {
                            if (innerSource.State != null) {
                                innerSource.State.Cancel();
                            }
                        }

                        innerSource.UtfprControlEnabled = enabled;
                    }
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// Enable/Disable the first level of inner details (i.e., innerNavigator.NavigatorSource == rootNavigator)
        /// </summary>
        public static void firstLevelInnerDetailsEnabled(UtfprBindingNavigatorBase navigator, bool enabled) {
            try {
                //getInnerSources(navigator).FirstOrDefault();
                foreach (var innerSource in getInnerSources(navigator)) {
                    if (innerSource != null && innerSource.NavigatorSource == navigator) {
                        if (navigator.DataSource is BindingSource) {
                            //if (innerSource.List.Count > 0) {
                            //if (innerSource.BindingSource.List.Count > 0) {
                            if (((BindingSource)innerSource.DataSource).List.Count > 0) {
                                innerSource.DeleteItem.UtfprControlEnabled = true;
                                innerSource.EditItem.UtfprControlEnabled = true;
                            } else {
                                innerSource.DeleteItem.UtfprControlEnabled = false;
                                innerSource.EditItem.UtfprControlEnabled = false;
                            }
                        }

                        innerSource.UtfprControlEnabled = true;
                    }
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        public static void innerLookupsEnabled(UtfprBindingNavigatorBase navigator, bool enabled) {
            try {
                foreach (var lookup in getInnerLookups(navigator)) {
                    //lookup.UtfprControlEnabled = enabled;
                    lookup.Enabled = enabled;
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        public static void boundLookupsEnabled(UtfprBindingNavigatorBase navigator, bool enabled) {
            try {
                foreach (var lookup in UtfprBindingNavigatorBaseHelper.getRootFormLookups(navigator)) {
                    if (lookup.DataSource != null) {
                        //foreach (Binding binding in lookup.DataBindings) {
                        //    if (binding.PropertyName == "LookupMember") {
                        //        //verifico se é um lookup de nível abaixo
                        //        if (navigator.DataSource == binding.DataSource) {
                        //        //if (navigator.BindingSource == binding.DataSource) {
                        //            lookup.UtfprControlEnabled = enabled;
                        //        }
                        //    }
                        //}

                        if (navigator.DataSource == lookup.LookupSource) {
                            lookup.UtfprControlEnabled = enabled;
                        }
                    }
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        public static void rootSourceDataGridsEnabled(UtfprBindingNavigatorBase navigator, bool enabled) {
            try {
                var rootSourceNavigator = findRootSourceNavigator(navigator);
                foreach (var grid in getRootFormDataGrids(navigator)) {
                    //if (rootSourceNavigator.BindingSource == grid.DataSource) {
                    if (rootSourceNavigator.DataSource == grid.DataSource) {
                        grid.Enabled = enabled;
                        grid.ReadOnly = true;
                        grid.AllowUserToAddRows = false;
                    }
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        public static void boundDataGridsEnabled(UtfprBindingNavigatorBase navigator, bool enabled) {
            try {
                foreach (var grid in getRootFormDataGrids(navigator)) {
                    if (navigator.DataSource == grid.DataSource) {
                        //if (navigator.BindingSource == grid.DataSource) {
                        grid.Enabled = enabled;
                        grid.ReadOnly = true;
                        grid.AllowUserToAddRows = false;
                    }
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        public static void boundDataGridsReadOnly(UtfprBindingNavigatorBase navigator, bool isReadOnly) {
            try {
                foreach (var grid in getRootFormDataGrids(navigator)) {
                    if (navigator.DataSource == grid.DataSource) {
                        grid.ReadOnly = isReadOnly;
                    }
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        public static void allDataGridsEnabled(UtfprBindingNavigatorBase navigator, bool enabled) {
            try {
                var rootSourceNavigator = findRootSourceNavigator(navigator);
                foreach (var grid in getRootFormDataGrids(navigator)) {
                    grid.Enabled = enabled;
                    grid.ReadOnly = true;
                    grid.AllowUserToAddRows = false;
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        #endregion

        #region clear

        /// <summary>
        /// TODO
        /// </summary>
        public static void clearRootFormLookups(UtfprBindingNavigatorBase navigator) {
            try {
                foreach (var lookup in UtfprBindingNavigatorBaseHelper.getRootFormLookups(navigator)) {
                    if (lookup.DataSource != null) {
                        ((BindingSource)lookup.DataSource).Clear();
                    }
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="navigator"></param>
        public static void clearRootSourceBindingSources(UtfprBindingNavigatorBase navigator) {
            try {
                var rootSourceNavigator = findRootSourceNavigator(navigator);

                //BindingListView
                //==================================
                //rootSourceNavigator.BindingSource.Clear();

                //if (navigator.RootEntity != null) {
                //    Type generic = typeof(BindingListView<>).MakeGenericType(new Type[] { navigator.RootEntity.GetType() });
                //    rootSourceNavigator.BindingSource.DataSource = Activator.CreateInstance(generic, new object[] { new List<object>() });
                //}

                //==================================

                foreach (var details in rootSourceNavigator.UBNDetails) {
                    //nao esta legal
                    ((BindingSource)details.DataSource).Clear();
                    //details.BindingSource.Clear();
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        public static void clearInnerLookups(UtfprBindingNavigatorBase navigator) {
            try {
                foreach (var lookup in getInnerLookups(navigator)) {
                    ((BindingSource)lookup.DataSource).Clear();
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        #endregion

        #region add/remove

        /// <summary>
        /// Populates a UtfprBindingNavigatorBase with all the details navigators of the root form
        /// </summary>
        /// <param name="navigator">the UtfprBindingNavigatorBase to be populated</param>
        public static void populateWithDetailsNavigators(UtfprBindingNavigatorBase navigator) {
            try {
                if (navigator.CurrentMode == UBNModeEnum.Master) {
                    foreach (var formNavigator in getRootFormNavigators(navigator)) {
                        if (formNavigator != navigator && formNavigator.CurrentMode == UBNModeEnum.Details) {
                            navigator.UBNDetails.Add(formNavigator);
                        }
                    }
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        internal static void removeFromRootSourceNavigator(UtfprBindingNavigatorBase navigator) {
            try {
                var rootSource = findRootSourceNavigator(navigator);
                if (rootSource != null) {
                    removeFromNavigatorSources(navigator);
                    rootSource.UBNDetails.Remove(navigator);
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        internal static void removeFromNavigatorSources(UtfprBindingNavigatorBase navigator) {
            try {
                var rootSource = findRootSourceNavigator(navigator);
                if (rootSource != null) {
                    foreach (var details in rootSource.UBNDetails) {
                        if (details.NavigatorSource == navigator) {
                            details.NavigatorSource = null;
                        }
                    }
                }
            } catch (Exception ex) {
                throw new UtfprWFCoreHelpersException("", ex);
            }
        }

        #endregion
    }
}
